/** @file lzostream.h
	@brief LZO compress / decompress filter for streams */

#ifndef G3_LZOSTREAM_H
#define G3_LZOSTREAM_H

#include "f_zstream.h"

#include <lzoconf.h>
#include <lzo1x.h>

/** Formulas for LZO packed / unpacked data sizes */
#define LZO_PACKED_SIZE(a)      (a + a / 16 + 64 + 3)
#define LZO_UNPACKED_SIZE(a)    ((100 * a) / 38)

namespace G3 {

/** @class LZOSTREAM
	@brief LZO compressing / decompressing filter */
class LZOSTREAM: public ZSTREAM {
	public:
        /**
            @brief A constructor that sets the pointer to the stream
        */
		LZOSTREAM (G3::STREAM *stream);
        /**
            @brief Just a destructor
        */
		~LZOSTREAM ();

//==============================================================================
// Opens a ZFILESTREAM either for Deflating or Inflating data..
//
//		byte OpenFlags				Flags for the stream
//				ZSTREAM_DEFLATE		Opens for deflating (compressed buffering)
//				ZSTREAM_INFLATE		Opens for inflating (decompressed reading)
//
//		int Level					Compression level
//				-1					Default, level 6
//				0					No compression at all
//				1 ... 9				Lowest ... Hightest compression
//
//	Returns true if successful
//==============================================================================
        /**
            @brief Opens a ZFILESTREAM either for Deflating or Inflating data
            @param[in] openFlags Flags for the stream.<br />
            <b>ZSTREAM_DEFLATE</b> - opens for deflating (compressed buffering)<br />
            <b>ZSTREAM_INFLATE</b> (default) - opens for inflating (decompressed buffering).
            @param[in] level Compression level.<br />
            <b>-1</b> default,<br />
            <b>0</b> no compression,<br />
            <b>1</b> ... <b>9</b> lowest to highest compression.
            @return True on success, false on failure
        */
		bool Open (byte openFlags = ZSTREAM_INFLATE, int level = -1);

        /**
            @brief Closes the ZFILESTREAM
        */
		void Close ();

        /**
            @brief Compresses data and adds it to the stream buffer
            @param[in] pointer Pointer to a memory block from where to compress
            @param[in] size Number of bytes to compress
            @return True on success, false on failure
        */
		bool Deflate (byte *pointer = NULL, long size = 0);

        /**
            @brief Reads data from the stream and decompresses it
            @param[out] pointer Pointer to a memory block where the data is stored
            @param[in] size Number of bytes saved at the Pointer
            @return Yhe number of bytes stored at Pointer
        */
		long Inflate (byte *pointer, long size);

        /**
            @brief Reads data into the stream and decompresses it
            @param[in] pointer Pointer to a memory block where the data is read from
            @param[in] size Number of bytes saved into the stream
            @return The number of bytes stored into the stream
        */
		long InflateIn (byte *pointer, long size);

        /**
            @brief Compresses data from the stream
            @param[out] pointer Pointer to a memory block where to compress
            @param[in] size Number of bytes to compress
            @return The number of bytes compressed
        */
		long DeflateOut (byte *pointer, long size = 0);

        /**
            @brief Reads data from a file and decompresses it
            @param[in] filename Name of the file to buffer
            @param[in] size Number of bytes to buffer (-1 or 0 for the whole file)
            @param[in] position Where in the file should we start reading
            @return The number of bytes read
        */
		long InflateFromFile (const string &filename, long size = -1, long position = 0);

//==============================================================================
// Reads data from the stream and compresses it into a file
//
//		const char *Filename	Name of the file to store the data in
//
//		long Size				Number of bytes read from the stream
//				-1, 0			Reads the whole stream buffer
//
//		long Position			Where to write into the file
//
//	Returns the number of bytes read
//==============================================================================
        /**
            @brief Reads data from the stream and compresses it into a file
            @param[in] filename Name of the file to store the data in
            @param[in] size Number of bytes to read from the stream (-1 or 0 for the whole buffer)
            @param[in] position Where to write into the file
            @return The number of bytes read
        */
		long DeflateToFile (const string &filename, long size = -1, long position = 0);

    private:
        /**
            @brief Calls LZO functions according to the value of the compressionLevel member
            @param[in] pointer Data to compress
            @param[in] size Number of bytes to compress
            @param[out] pOut Pointer to the compressed data buffer
            @return The number of bytes read
        */
		long DoCompress (byte *pointer, long size, byte *pOut);
};

}

#endif
